package com.xb.loan.usercenter.account.impl;

import com.xb.loan.account.service.ICouponService;
import com.xb.loan.account.service.bean.CouponBillVO;
import com.xb.loan.account.service.bean.CouponInfoVO;
import com.xb.loan.account.service.constant.AccountConst;
import com.xb.loan.account.service.exception.IAccountServiceException;
import com.xb.loan.log.exception.BizException;
import com.xb.loan.usercenter.account.common.VerifySet;
import com.xb.loan.usercenter.account.dao.CouponBillDao;
import com.xb.loan.usercenter.account.dao.CouponInfoDao;
import com.xb.loan.usercenter.account.dao.bean.CouponBill;
import com.xb.loan.usercenter.account.dao.bean.CouponInfo;
import com.xb.loan.usercenter.service.user.bean.UserInfoVO;
import com.xb.loan.util.cache.redis.comm.FormatOperation;
import com.xb.loan.util.common.ObjectOperation;
import com.xb.loan.util.log.DefaultLoggerFacotry;
import com.xb.loan.util.log.LogFormatTemplate;
import com.xb.loan.util.log.LogFormatUtil;
import com.xb.loan.util.mybatis.MyTransactional;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 北京掌中彩信息科技有限公司源代码，版权归北京掌中彩信息科技有限公司所有。
 * 
 * 项目名称 : common-biz 创建日期 : 2015年9月9日 类 描 述 : 礼券账户服务接口 修改历史 : 1. [2015年9月9日]创建文件
 * by zhiqiang.zhang
 */
@Service("couponService")
public class CouponServiceImpl implements ICouponService, IAccountServiceException {
	Logger logger = DefaultLoggerFacotry.getLogger(CouponServiceImpl.class);

	@Autowired
	private CouponInfoDao couponInfoDao;

	@Autowired
	private CouponBillDao couponBillDao;

	@Autowired
	// ① 注入上下文
	private ApplicationContext context;
	private CouponServiceImpl proxySelf; // ② 表示代理对象，不是目标对象

	@PostConstruct
	// ③ 初始化方法
	private void setSelf() {
		// 从上下文获取代理对象（如果通过proxtSelf=this是不对的，this是目标对象）
		// 此种方法不适合于prototype Bean，因为每次getBean返回一个新的Bean
		proxySelf = (CouponServiceImpl) context.getBean(ICouponService.class);
	}

	@Override
	public String addCoupon(String foreignId, UserInfoVO userInfoVO, CouponInfoVO couponInfoVO, int billType, String accoutPeriod) throws BizException {
		String couponId = proxySelf.addCouponTransaction(foreignId, userInfoVO, couponInfoVO, billType, accoutPeriod);

		logger.info(LogFormatTemplate.COUPON_SERVICE_ADD_COUPON, new String[] { "coupon", userInfoVO.getUserId(), couponId });

		return couponId;

	}

	@MyTransactional
	public String addCouponTransaction(String foreignId, UserInfoVO userInfoVO, CouponInfoVO couponInfoVO, int billType, String accoutPeriod) {
		// 礼券ID
		String couponId = FormatOperation.assemblySeq(AccountConst.PriKey_Name, AccountConst.PriKey_Length);
		couponInfoVO.setCouponId(couponId);
		couponInfoVO.setAccountId(userInfoVO.getAccountId());
		couponInfoVO.setMoney(couponInfoVO.getTotalMoney());

		CouponInfo couponInfo = ObjectOperation.convertByClasses(couponInfoVO, CouponInfo.class);

		couponInfoDao.insert(couponInfo);

		// 礼券帐务ID
		String couponBillId = FormatOperation.assemblySeq(AccountConst.PriKey_Name, AccountConst.PriKey_Length);
		CouponBill couponBill = new CouponBill();
		couponBill.setBillId(couponBillId);
		couponBill.setUserId(userInfoVO.getUserId());
		couponBill.setAccountId(userInfoVO.getAccountId());
		couponBill.setActivitiesId(couponInfoVO.getActivitiesId());
		couponBill.setCouponId(couponId);
		couponBill.setPartnerId(userInfoVO.getPartnerId());
		couponBill.setFeeType(AccountConst.FeeType_Default);
		couponBill.setBillType(billType);
		couponBill.setLastMoney(0);
		couponBill.setBillIncome(couponInfoVO.getTotalMoney());
		couponBill.setBillExpend(0d);
		couponBill.setCurMoney(couponInfoVO.getTotalMoney());
		couponBill.setAccoutPeriod(accoutPeriod);
		couponBill.setForigenId(foreignId);

		couponBillDao.insert(couponBill);

		return couponId;
	}

	@Override
	public void deductCoupon(String foreignId, UserInfoVO userInfoVO, String couponId, double money, int billType, String accoutPeriod) throws BizException {
		CouponInfo couponInfo = queryCouponInfo(couponId);
		VerifySet.verifyCouponInfoIsNormal(couponInfo);

		// 金额不足返回false
		if (couponInfo.getMoney() < money)
			throw IAccountServiceException.noEnoughMoney;

		proxySelf.deductCouponTransaction(couponInfo, foreignId, userInfoVO, money, billType, accoutPeriod);
		logger.info(LogFormatTemplate.COUPON_SERVICE_DEDUCT_COUPON, new String[] { "coupon", userInfoVO.getUserId(), couponId, String.valueOf(money) });

	}

	/**
	 * 查询礼券基本信息
	 * @param couponId
	 * @return
	 * @throws BizException 2015年9月10日 by zhiqiang.zhang
	 */
	private CouponInfo queryCouponInfo(String couponId) throws BizException {
		CouponInfo couponInfo = couponInfoDao.queryCouponInfoById(couponId);
		return couponInfo;
	}

	@MyTransactional
	public void deductCouponTransaction(CouponInfo couponInfo, String foreignId, UserInfoVO userInfoVO, double money, int billType, String accoutPeriod) throws BizException {
		double lastMoney = couponInfo.getMoney();
		
		// 礼券基本信息
		couponInfo.setMoney(money);
		int resultNum = couponInfoDao.deductMoney(couponInfo);
		// 没有修改记录
		if (resultNum < 1) {
			// 处理失败
			throw IAccountServiceException.noEnoughMoney;
		}
		// 防止有其他扣钱处理，此处再次查询礼券信息
		couponInfo = this.queryCouponInfo(couponInfo.getCouponId());

		// 礼券帐务ID
		String couponBillId = FormatOperation.assemblySeq(AccountConst.PriKey_Name, AccountConst.PriKey_Length);

		CouponBill couponBill = new CouponBill();
		couponBill.setBillId(couponBillId);
		couponBill.setUserId(userInfoVO.getUserId());
		couponBill.setAccountId(userInfoVO.getAccountId());
		couponBill.setActivitiesId(couponInfo.getActivitiesId());
		couponBill.setCouponId(couponInfo.getCouponId());
		couponBill.setPartnerId(userInfoVO.getPartnerId());
		couponBill.setFeeType(AccountConst.FeeType_Default);
		couponBill.setBillType(billType);
		couponBill.setLastMoney(lastMoney);
		couponBill.setBillExpend(money);
		couponBill.setCurMoney(couponInfo.getMoney());
		couponBill.setAccoutPeriod(accoutPeriod);
		couponBill.setForigenId(foreignId);

		couponBillDao.insert(couponBill);

	}

	@Override
	public int updateCouponInfo(CouponInfoVO couponInfoVO) throws BizException {
		VerifySet.verifyCouponInfoVO(couponInfoVO);
		VerifySet.verifyCouponId(couponInfoVO.getCouponId());

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("couponId", couponInfoVO.getCouponId());
		params.put("startTime", couponInfoVO.getStartTime());
		params.put("endTime", couponInfoVO.getEndTime());
		params.put("status", couponInfoVO.getStatus());

		int result = couponInfoDao.updateAccountCoupon(params);
		logger.info(LogFormatTemplate.COUPON_SERVICE_UPDATE_COUPON_INFO, new String[] { "coupon", couponInfoVO.getCouponId() });

		return result;
	}

	@Override
	public List<CouponInfoVO> queryCouponInfo(String accountId, String activitiesId, String couponId, String startDate, String endDate, int pageNum, int numPerPage) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>(7);

		params.put("accountId", accountId);
		params.put("activitiesId", activitiesId);
		params.put("couponId", couponId);
		params.put("startDate", startDate);
		params.put("endDate", endDate);

		params.put("pageNum", pageNum);
		params.put("numPerPage", numPerPage);

		List<CouponInfo> couponInfoList = couponInfoDao.queryCouponInfo(params);

		List<CouponInfoVO> result = ObjectOperation.convertByClassesList(couponInfoList, CouponInfoVO.class);
		logger.info(LogFormatTemplate.COUPON_SERVICE_QUERY_COUPON_INFO, new String[] { "coupon", accountId, activitiesId, couponId, startDate, endDate, String.valueOf(pageNum), String.valueOf(numPerPage) });

		return result;

	}

	@Override
	public int queryCouponInfoCount(String accountId, String activitiesId, String couponId, String startDate, String endDate) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>(5);

		params.put("accountId", accountId);
		params.put("activitiesId", activitiesId);
		params.put("couponId", couponId);
		params.put("startDate", startDate);
		params.put("endDate", endDate);

		int result = couponInfoDao.queryCouponInfoCount(params);
		logger.info(LogFormatTemplate.COUPON_SERVICE_QUERY_COUPON_INFO_COUNT, new String[] { "coupon", accountId, activitiesId, couponId, startDate, endDate });

		return result;
	}

	@Override
	public List<CouponBillVO> queryCouponBill(String accountId, String activitiesId, String couponId, Integer feeType, Integer billType, String startDate, String endDate, int pageNum, int numPerPage) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>(9);

		params.put("accountId", accountId);
		params.put("activitiesId", activitiesId);
		params.put("couponId", couponId);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("feeType", feeType);
		params.put("billType", billType);

		params.put("pageNum", pageNum);
		params.put("numPerPage", numPerPage);

		List<CouponBill> couponBillList = this.couponBillDao.queryCouponBill(params);

		List<CouponBillVO> result = ObjectOperation.convertByClassesList(couponBillList, CouponBillVO.class);
		logger.info(LogFormatTemplate.COUPON_SERVICE_QUERY_COUPON_BILL, new String[] { "coupon", accountId, activitiesId, couponId, feeType == null ? "null" : String.valueOf(feeType), feeType == null ? "null" : String.valueOf(billType), startDate, endDate, String.valueOf(pageNum), String.valueOf(numPerPage) });

		return result;
	}

	@Override
	public int queryCouponBillCount(String accountId, String activitiesId, String couponId, Integer feeType, Integer billType, String startDate, String endDate) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>(7);

		params.put("accountId", accountId);
		params.put("activitiesId", activitiesId);
		params.put("couponId", couponId);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("feeType", feeType);
		params.put("billType", billType);

		int result = this.couponBillDao.queryCouponBillCount(params);

		logger.info(LogFormatTemplate.COUPON_SERVICE_QUERY_COUPON_BILL_COUNT, new String[] { "coupon", accountId, activitiesId, couponId, feeType == null ? "null" : String.valueOf(feeType), feeType == null ? "null" : String.valueOf(billType), startDate, endDate });

		return result;

	}

	@Override
	public void flushes(String userId, String foreignId, int billType) throws BizException {
		if(billType != AccountConst.BillType_Encash || billType != AccountConst.BillType_Purchase_Lottery){
			logger.error(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "billType", "msg"},
					new Object[]{"account", foreignId, billType, IAccountServiceException.invalidFlushesType.getMessage()}));
			throw IAccountServiceException.invalidFlushesType;
		}
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("foreignId", foreignId);
		params.put("billType", billType);
		params.put("isFlushes", AccountConst.Flushes_No);
		
		List<CouponBill> bills = couponBillDao.queryCouponBill(params);
		if(bills == null || bills.size() <= 0)
			return;
		
		CouponBill target = bills.get(0);
		Map<String, Object> billParams = new HashMap<String, Object>();
		billParams.put("billId", target.getBillId());
		billParams.put("isFlushes", AccountConst.Flushes_Yes);
		
		Map<String, Object> flushesParams = new HashMap<String, Object>();
		flushesParams.put("accountId", target.getAccountId());
		flushesParams.put("money", target.getBillExpend());
		
		flushesTransaction(billParams, flushesParams);
	}

	private void flushesTransaction(Map<String, Object> billParams,
			Map<String, Object> flushesParams) {
		couponBillDao.flushes(billParams);
		couponInfoDao.flushes(flushesParams);
	}

}
